﻿using System;
using System.Net.Sockets;
using System.Threading;

namespace Jiubang.Communication.Server {
    internal sealed class AsyncUserToken {
        #region TokenState enum

        /// <summary>
        ///   该值大于0时表示未完成发送任务数
        /// </summary>
        public enum TokenState {
            /// <summary>
            ///   表示发送任务完成
            /// </summary>
            Completed = 0,
            /// <summary>
            ///   当前任务为接收消息头部
            /// </summary>
            Head = -1,
            /// <summary>
            ///   读取消息正文内容
            /// </summary>
            Body = -2,
            /// <summary>
            ///   接收新Socket
            /// </summary>
            Accept = -3,
            /// <summary>
            ///   注册Socket
            /// </summary>
            FirstMessage = -4,
        }

        #endregion

        private int _state;

        /// <summary>
        ///   是否主标识
        /// </summary>
        public bool IsMaster {
            get { return MasterEventArgs == null; }
        }

        public int State {
            get { return _state; }
            set { _state = value; }
        }

        /// <summary>
        ///   消息头（包括长度标识）在缓冲区中的偏移量。
        /// </summary>
        public int MessageHeaderOffset { get; set; }

        public SocketAsyncEventArgs MasterEventArgs { get; private set; }

        /// <summary>
        ///   返回群发流程待发送任务数,线程安全方法<br />
        /// </summary>
        /// <returns></returns>
        public int CompleteTask() {
            var master = MasterEventArgs;
            var userToken = master == null? this: (AsyncUserToken) master.UserToken;
            return Interlocked.Decrement(ref userToken._state);
        }

        /// <summary>
        ///   向主标识添加待完成任务数.
        /// </summary>
        public void AddTo(SocketAsyncEventArgs masterArgs) {
            if (masterArgs == null) 
                throw new ArgumentNullException("masterArgs");
            if (!IsMaster)
                throw new InvalidOperationException("已经对当前对象设置主标识");

            MasterEventArgs = masterArgs;
            Interlocked.Increment(ref ((AsyncUserToken)masterArgs.UserToken)._state);
        }

        public void Reset() {
            _state = 0;
            MasterEventArgs = null;
        }
    }
}